#ifndef __ACTION_H
#define __ACTION_H

#include "direction.h"
#include "rect.h"
#include "map.h"

#define COOLDOWN_TURN 0
#define COOLDOWN_MOVE TILE_SIZE
#define COOLDOWN_HALT 0
#define COOLDOWN_ATTACK (3*FPS/10)
#define COOLDOWN_TRAVERSE 1
#define COOLDOWN_DIE (12*FPS/10)
#define COOLDOWN_RESPAWN 0

typedef enum {
	ACTION_NONE = 0,
	ACTION_TURN,         // actor turns to face a new direction
	ACTION_MOVE,         // actor travels from tile to tile
	ACTION_HALT,         // actor stands still
	ACTION_ATTACK_CLOSE, // actor attacks with close weapon
	ACTION_ATTACK_RANGE, // actor attacks with ranged weapon
	ACTION_TRAVERSE,     // actor enters teleporters or stairs
	ACTION_DIE,          // actor dies
	ACTION_RESPAWN       // actor respawns
} ActionType;

typedef struct {
	int weapon;
} CloseAttackAction;

typedef struct {
	int weapon;
} RangeAttackAction;

typedef struct {
	coord_t target;
} TraverseAction;

typedef struct {
	ActionType type;
	int actor;
	int start_time; // Game time in ticks when this action start(ed)
	int cooldown;
	
	coord_t location; // Where the actor is standing
	Direction dir;    // Which direction the actor is facing
	
	union {
		CloseAttackAction* cattack;
		RangeAttackAction* rattack;
		TraverseAction* traverse;
	};
} Action;

extern const Action no_action;

extern Action action_alloc_turn (int actor, int start_time, Direction dir);
extern Action action_alloc_move (int actor, int start_time, Direction dir);
extern Action action_alloc_halt (int actor, int start_time);
extern Action action_alloc_closeattack (int actor, int start_time, int weapon);
extern Action action_alloc_rangeattack (int actor, int start_time, int weapon);
extern Action action_alloc_traverse (int actor, int start_time, coord_t target);
extern Action action_alloc_die (int actor, int start_time);
extern Action action_alloc_respawn (int actor, int start_time);
extern void action_free (Action* a);
extern int action_is_equal (const Action* a1, const Action* a2);

struct Player;
// extern struct Monster; // reserved for later use

/*
 * About actors:
 * Every action has an actor ID (int). This number describes which
 * entity on the game board is executing the action at hand. Actors
 * can be players or monsters. The following methods can be used to
 * correlate the actor ID with the corresponding object and determine
 * an actor's type.
 */
typedef enum { ACTOR_INVALID, ACTOR_PLAYER, ACTOR_MONSTER } ActorType;
extern int actor_id_from_player (struct Player* player_obj);
// int get_actor_id_from_monster (Monster* monster_obj); // reserved for later use
extern ActorType actor_type (int id);
extern struct Player* player_from_actor_id (int id);
// Monster* monster_from_actor_id (int id); // reserved for later use

#endif
